package safe;

import java.util.concurrent.TimeUnit;

/**
 * @author lzm
 * @date 2025/2/20 20:02
 * @description 多线程版的累加器 - 使用CAS解决线程不靠谱问题
 */
public class AdderV5 {

    int i = 0;

    /**
     * 多线程版的累加器
     */
    public void add() throws InterruptedException {
        // 为每个线程创建计算任务
        Runnable task = () -> {
            // 将变量i加1，重复这个操作10000次
            for (int j = 0; j < 10000; j++) {
                // 使用CAS操作的+1
                int expectedValue;
                int newValue;
                do {
                    expectedValue = i;
                    newValue = expectedValue + 1;
                } while (!compareAndSet(expectedValue, newValue));
            }
        };
        // 一共有5个线程，每个线程都对变量i进行一万次+1的操作
        for (int j = 0; j < 5; j++) {
            new Thread(task, "线程-" + j).start();
        }
        TimeUnit.SECONDS.sleep(1);
    }

    /**
     * 模拟CAS实现
     * @param expectedValue 预期值，也就是每个线程修改前读到的变量值
     * @param newValue      每个线程修改后的新值
     * @return 比较结果
     * 注意事项：
     *      1. 该方法必须要使用synchronized关键字修饰，否则仍然会出现线程不靠谱问题
     *      2. 真正的CAS操作一般是使用unsafe类实现的，我这里只是模拟了一下
     */
    private synchronized boolean compareAndSet(int expectedValue, int newValue) {
        // 比较并交换
        if (i == expectedValue) {
            i = newValue;
            return true;
        }
        return false;
    }


    public static void main(String[] args) throws InterruptedException {
        AdderV5 adder = new AdderV5();
        adder.add();
        System.out.println("计算结果是：" + adder.i);
    }

}
